package com.floreantpos.ui.model;

import com.floreantpos.main.Application;
import com.floreantpos.model.ActionHistory;
import com.floreantpos.model.Guest;
import com.floreantpos.model.PayOutTransaction;
import com.floreantpos.model.Terminal;
import com.floreantpos.model.dao.ActionHistoryDAO;
import com.floreantpos.model.dao.GuestDAO;
import com.floreantpos.model.dao.PayOutTransactionDAO;
import com.floreantpos.swing.FixedLengthDocument;
import com.floreantpos.swing.MessageDialog;
import com.floreantpos.ui.BeanEditor;
import com.floreantpos.ui.dialog.POSMessageDialog;
import com.floreantpos.util.POSUtil;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.ParseException;
import java.util.Date;
import java.util.Locale;
import javax.swing.JFormattedTextField;
import javax.swing.JOptionPane;
import javax.swing.text.MaskFormatter;

public class GuestForm extends BeanEditor {

  private int currentGuestId;
  
  private Double currentBalance = Double.valueOf(0);
  
  private DecimalFormat decimalFormat = new DecimalFormat("#,##0.00", new DecimalFormatSymbols(new Locale("pt", "BR")));

  /**
   * Creates new form CategoryBeanEditor
   */
  public GuestForm() throws Exception {
    this(new Guest());
  }

  public GuestForm(Guest guest) throws Exception {
    initComponents();

    tfName.setDocument(new FixedLengthDocument(40));
    tfTelephone.setDocument(new FixedLengthDocument(16));
    tfAddressLine1.setDocument(new FixedLengthDocument(40));
    tfAddressLine2.setDocument(new FixedLengthDocument(40));
    tfAddressLine3.setDocument(new FixedLengthDocument(40));
    tfDeliveryCharge.setDocument(new FixedLengthDocument(6));
    tfTaxId.setDocument(new FixedLengthDocument(32));
    tfCurrentBalance.setDocument(new FixedLengthDocument(6));

    if (guest.getId() != null) {
      currentGuestId = guest.getId();
    }

    setBean(guest);
  }

  public String getDisplayText() {
    Guest guest = (Guest) getBean();
    if (guest.getId() == null) {
      return "Incluir Cliente";
    }
    return "Alterar Cliente";
  }

  private void initComponents() {

    jLabel1 = new javax.swing.JLabel();
    tfName = new com.floreantpos.swing.FixedLengthTextField();
    jLabel1.setText(com.floreantpos.POSConstants.NAME + ":");

    jLabel2 = new javax.swing.JLabel();
    tfTelephone = new JFormattedTextField(createFormatter("(##) *####-####"));
    jLabel2.setText(com.floreantpos.POSConstants.TELEPHONE + ":");

    jLabel3 = new javax.swing.JLabel();
    tfAddressLine1 = new com.floreantpos.swing.FixedLengthTextField();
    jLabel3.setText(com.floreantpos.POSConstants.ADDRESS_LINE1);

    jLabel4 = new javax.swing.JLabel();
    tfAddressLine2 = new com.floreantpos.swing.FixedLengthTextField();
    jLabel4.setText(com.floreantpos.POSConstants.ADDRESS_LINE2);

    jLabel5 = new javax.swing.JLabel();
    tfAddressLine3 = new com.floreantpos.swing.FixedLengthTextField();
    jLabel5.setText(com.floreantpos.POSConstants.ADDRESS_LINE3);

    jLabel6 = new javax.swing.JLabel();
    tfDeliveryCharge = new com.floreantpos.swing.FixedLengthTextField();
    jLabel6.setText("Taxa de Entrega:");
    
    jLabel7 = new javax.swing.JLabel();
    tfTaxId = new com.floreantpos.swing.FixedLengthTextField();
    jLabel7.setText("Documento:");    
    
    jLabel8 = new javax.swing.JLabel();
    tfCurrentBalance = new com.floreantpos.swing.FixedLengthTextField();
    jLabel8.setText("Saldo Atual:");    

    org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(this);
    this.setLayout(layout);
    layout.setHorizontalGroup(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING).add(
            org.jdesktop.layout.GroupLayout.LEADING,
            layout.createSequentialGroup().addContainerGap().add(
                    layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING).add(
                            org.jdesktop.layout.GroupLayout.LEADING,
                            layout.createSequentialGroup()
                            .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                                    .add(jLabel1)
                                    .add(jLabel7)
                                    .add(jLabel2)
                                    .add(jLabel3)
                                    .add(jLabel4)
                                    .add(jLabel5)
                                    .add(jLabel6)
                                    .add(jLabel8))
                            .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                            .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING, false)
                                    .add(tfName, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 288, Short.MAX_VALUE)
                                    .add(tfTaxId, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 110, Short.MAX_VALUE)
                                    .add(tfTelephone, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 110, Short.MAX_VALUE)
                                    .add(tfAddressLine1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 288, Short.MAX_VALUE)
                                    .add(tfAddressLine2, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 288, Short.MAX_VALUE)
                                    .add(tfAddressLine3, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 288, Short.MAX_VALUE)
                                    .add(tfDeliveryCharge, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 288, Short.MAX_VALUE)
                                    .add(tfCurrentBalance, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 288, Short.MAX_VALUE))))));
    layout.setVerticalGroup(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING).add(
            layout.createSequentialGroup().addContainerGap().add(
                    layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE).add(jLabel1).add(tfName, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE,
                            org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)).addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED).add(
                    layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE).add(jLabel7).add(tfTaxId, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE,
                            org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)).addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED).add(                                    
                    layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE).add(jLabel2).add(tfTelephone, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE,
                            org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)).addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED).add(
                    layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE).add(jLabel3).add(tfAddressLine1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE,
                            org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)).addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED).add(
                    layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE).add(jLabel4).add(tfAddressLine2, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE,
                            org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)).addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED).add(
                    layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE).add(jLabel5).add(tfAddressLine3, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE,
                            org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)).addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED).add(
                    layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE).add(jLabel6).add(tfDeliveryCharge, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE,
                            org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)).addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED).add(                                    
                    layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE).add(jLabel8).add(tfCurrentBalance, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE,
                            org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)).addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)));
  }

  protected void updateView() {
    Guest guest = (Guest) getBean();
    if (guest == null) {
      tfName.setText("");
      tfTaxId.setText("");
      tfTelephone.setText("");
      tfAddressLine1.setText("");
      tfAddressLine2.setText("");
      tfAddressLine3.setText("");
      tfDeliveryCharge.setText("");
      tfCurrentBalance.setText("");
      return;
    }
    tfName.setText(guest.getName());
    tfTaxId.setText(guest.getTaxId());
    tfTelephone.setText(guest.getTelephone());
    tfAddressLine1.setText(guest.getAddressLine1());
    tfAddressLine2.setText(guest.getAddressLine2());
    tfAddressLine3.setText(guest.getAddressLine3());
    tfDeliveryCharge.setText(Application.formatNumber(guest.getDeliveryCharge()));
    tfCurrentBalance.setText(Application.formatNumber(guest.getCurrentBalance()));
    
    currentBalance = guest.getCurrentBalance();
  }

  protected boolean updateModel() {
    Guest guest = (Guest) getBean();
    if (guest == null) {
      return false;
    }

    String name = tfName.getText();
    if (POSUtil.isBlankOrNull(name)) {
      MessageDialog.showError("O Nome é obrigatório");
      return false;
    }

    String telephone = tfTelephone.getText();
    if (POSUtil.isBlankOrNull(telephone)) {
      MessageDialog.showError("O Telefone é obrigatório");
      return false;
    }

    int existingGuestId = currentGuestId;

    GuestDAO dao = new GuestDAO();
    Guest existingGuest = dao.findGuestByTelephone(telephone);

    if (existingGuest != null) {
      existingGuestId = existingGuest.getId();
    }

    if (existingGuestId != currentGuestId) {
      MessageDialog.showError("Telefone já cadastrado");
      return false;
    }
    
    String taxId = tfTaxId.getText();
    
    if (!taxId.isEmpty()) {
      
      taxId = POSUtil.checkTaxId(taxId);
      
      if (taxId.equals("*")) {
        MessageDialog.showError("Documento Inválido");
        return false;          
      }

      existingGuestId = currentGuestId;
      existingGuest = dao.findGuestByTaxId(taxId);

      if (existingGuest != null) {
        existingGuestId = existingGuest.getId();
      }

      if (existingGuestId != currentGuestId) {
        MessageDialog.showError("Documento já cadastrado");
        return false;
      }          
    }

    String addressLine1 = tfAddressLine1.getText();
    if (POSUtil.isBlankOrNull(addressLine1)) {
      MessageDialog.showError("O Endereço 1 é obrigatório");
      return false;
    }

    String addressLine2 = tfAddressLine2.getText();

    String addressLine3 = tfAddressLine3.getText();

    Double deliveryCharge = Double.valueOf(0);
    try {
      deliveryCharge = Double.valueOf(decimalFormat.parse(tfDeliveryCharge.getText()).doubleValue());
    } catch (ParseException ex) {
      MessageDialog.showError("Taxa de Entrega Inválida");
      return false;
    }
    
    Double newBalance = Double.valueOf(0);
    try {
      newBalance = Double.valueOf(decimalFormat.parse(tfCurrentBalance.getText()).doubleValue());
    } catch (ParseException ex) {
      MessageDialog.showError("Saldo Atual Inválido");
      return false;
    }
    
    if (newBalance < 0) {
      MessageDialog.showError("Não é possivel registrar manualmente um saldo devedor para o cliente.");
      return false;
    }
    
    if (newBalance > currentBalance) {
      MessageDialog.showError("Não é possível incrementar o saldo do cliente.\nUtilize o botão \"Receber\" da Janela Principal.");
      return false;      
    }
    
    if (newBalance < currentBalance) {
      Double payoutAmount = currentBalance - newBalance;
      String payoutNote = "Devolução do saldo do cliente: " + name + " " + telephone;
      if (doGuestPayout(payoutAmount, payoutNote)) {
         JOptionPane.showMessageDialog(null, "\nSaldo atualizado com sucesso, retire R$ " + Application.formatNumber(payoutAmount) + " do caixa.\n\n", com.floreantpos.POSConstants.MDS_POS, JOptionPane.INFORMATION_MESSAGE, null);
      } else {
        MessageDialog.showError("Não foi possível registrar o Pagamento ao Cliente.");
        return false;        
      }
    }

    guest.setName(name);
    guest.setTaxId(taxId);
    guest.setTelephone(telephone);
    guest.setAddressLine1(addressLine1);
    guest.setAddressLine2(addressLine2);
    guest.setAddressLine3(addressLine3);
    guest.setDeliveryCharge(deliveryCharge);
    guest.setCurrentBalance(newBalance);

    return true;
  }
  
  private Boolean doGuestPayout(Double payoutAmount, String payoutNote) {
    Application application = Application.getInstance();

    Terminal terminal = application.getTerminal();

    terminal.setCurrentBalance(terminal.getCurrentBalance() - payoutAmount);

    PayOutTransaction payOutTransaction = new PayOutTransaction();
    payOutTransaction.setNote(payoutNote);
    payOutTransaction.setSubtotalAmount(Double.valueOf(payoutAmount));
    payOutTransaction.setDiscountAmount(Double.valueOf(0));
    payOutTransaction.setTaxAmount(Double.valueOf(0));
    payOutTransaction.setTotalAmount(Double.valueOf(payoutAmount));

    payOutTransaction.setUser(Application.getCurrentUser());
    payOutTransaction.setTransactionTime(new Date());
    payOutTransaction.setTerminal(terminal);

    try {
      PayOutTransactionDAO dao = new PayOutTransactionDAO();
      dao.saveTransaction(payOutTransaction, terminal);

      String actionMessage = "";
      actionMessage += com.floreantpos.POSConstants.TOTAL + ": " + Application.formatNumber(payoutAmount);
      ActionHistoryDAO.getInstance().saveHistory(Application.getCurrentUser(), ActionHistory.PAY_OUT, actionMessage);

      return true;
      
    } catch (Exception e) {
      MessageDialog.showError(e.getMessage(), e);
      return false;
      
    }
  }  

  protected MaskFormatter createFormatter(String s) {
    MaskFormatter formatter = null;
    try {
      formatter = new MaskFormatter(s);
    } catch (Exception exc) {
      MessageDialog.showError("Telefone Inválido.\nMensagem: " + exc.getMessage());
    }
    return formatter;
  }

  private javax.swing.JLabel jLabel1;
  private com.floreantpos.swing.FixedLengthTextField tfName;

  private javax.swing.JLabel jLabel2;
  private javax.swing.JFormattedTextField tfTelephone;

  private javax.swing.JLabel jLabel3;
  private com.floreantpos.swing.FixedLengthTextField tfAddressLine1;

  private javax.swing.JLabel jLabel4;
  private com.floreantpos.swing.FixedLengthTextField tfAddressLine2;

  private javax.swing.JLabel jLabel5;
  private com.floreantpos.swing.FixedLengthTextField tfAddressLine3;

  private javax.swing.JLabel jLabel6;
  private com.floreantpos.swing.FixedLengthTextField tfDeliveryCharge;
  
  private javax.swing.JLabel jLabel7;
  private com.floreantpos.swing.FixedLengthTextField tfTaxId;  
  
  private javax.swing.JLabel jLabel8;
  private com.floreantpos.swing.FixedLengthTextField tfCurrentBalance;   

  @Override
  public boolean save() {
    try {
      if (!updateModel()) {
        return false;
      }

      Guest guest = (Guest) getBean();
      GuestDAO guestDAO = new GuestDAO();
      guestDAO.saveOrUpdate(guest);
      return true;
    } catch (Exception x) {
      MessageDialog.showError(x);
      return false;
    }
  }

  @Override
  public void dispose() {
  }
}
